﻿using System;
using RAP.Framework.Libary.DataSource;
using RAP.Framework.Libary.ServerCacheManager;
using System.Collections;
using RAP.Framework.Libary.Utils;
using RAP.Framework.Libary.Configuration;
using Microsoft.AspNetCore.Hosting;
using RAP.Framework.Libary.DataSource.Service.SQL;
using Microsoft.Extensions.Logging;
using AspectCore.Configuration;
using RAP.Framework.Libary.DataSource.Model.Attribute;
using RAP.Framework.Libary.SqlDataService.Interceptor;
using RAP.Framework.Libary.SqlDataService.Service;
using RAP.Web.Libary.Config;
using RAP.Framework.Libary.DataSource.Model;
using RAP.Web.Libary.Common.Model;
using RAP.Framework.Libary.DataSource.Context;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using RAP.Framework.Libary.DataSource.Model.DataSource;

namespace RAP.Web.Libary.Service.DataService
{
  /// <summary>
  /// SQL数据访问服务
  /// </summary>
  public class SqlDataService : SqlDataServiceBase
  {
    /// <summary>
    /// 数据源配置参数
    /// </summary>
    protected virtual IDictionary DataSources { get; set; }

    /// <summary>
    /// 初始化数据查询服务
    /// </summary>
    /// <param name="app"></param>
    /// <param name="logger"></param>
    public static void Initialize(IApplicationBuilder app, ILogger logger)
    {
      if (SiteSettingsBase.DataSourceConnectionPasswordKey.IsNotNullOrEmpty())
      {
        var connectionPW
          = DataSourceConfig.CONNECTION_STRING_PASSWORD_PREFIX
          = Environment.GetEnvironmentVariable(SiteSettingsBase.DataSourceConnectionPasswordKey);//从系统环境变量获取密码
        if (connectionPW.IsNullOrEmpty())
        {
          throw new Exception("数据库密码获取 [失败]！");
        }
        else
        {
          logger.LogInformation("数据库密码获取 [成功]！");
        }
      }
      else
      {
        logger.LogInformation("使用未加密的数据库连接字符串！");
      }
      if (SiteSettingsBase.IsDebug)
      {
        Debug.Info($"Connection Pass={DataSourceConfig.CONNECTION_STRING_PASSWORD_PREFIX}");
      }

      //配置数据模型的Interceptor对象和匹配规则
      DataSourceHelper.DataModelGenerator.Configure(service =>
      {
        var serviceProvider = app.ApplicationServices.GetService<IServiceProvider>();
        service.Configuration.Interceptors.AddTyped<SqlLazyLoadInterceptor<ISqlDataService>>(new object[] { serviceProvider }, new AspectPredicate(method =>
        {
          var methodName = method.Name;
          if (methodName == "SetContext" || methodName == "GetContext" || methodName.StartsWith("set_"))
          {
            return false;
          }
          if (methodName.StartsWith("get_"))
          {
            //如果是【属性】的get方法，则去掉“get_”前缀
            methodName = methodName.Substring(4);
          }
          return method.DeclaringType.GetMember(methodName).FirstItem().HasAttribute<LazyloadAttribute>();
        }));
      });

      //注册自定义数据访问底层对象
      DataSourceHelper.DataSourceFactory.Clear();
      DataSourceHelper.DataSourceFactory.Register(ServiceUtils.SERVICE_SQL_IDENTITY, () =>
      {
        var config = app.ApplicationServices.GetService<DataSourceConfig>();
        config.Initialize();
        return new SqlService(config);
      });
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="cache"></param>
    /// <param name="configurationManager"></param>
    /// <param name="serviceProvider"></param>
    public SqlDataService(
      ICacheManager cache,
      IConfigurationManager configurationManager,
      IServiceProvider serviceProvider) : base(cache, configurationManager, serviceProvider)
    {
      this.DataSources = configurationManager.GetValue<IDictionary>($"{SiteSettingsBase.DataConfigField}.{SiteSettingsBase.DataSourcesField}");
    }

    /// <summary>
    /// 获取有效的城市数据源的城市数据源Id
    /// </summary>
    /// <param name="cityCode"></param>
    /// <returns></returns>
    protected virtual string GetValidDataSource(string cityCode)
    {
      var dataSourceId = $"{SiteSettingsBase.DataSourceKeyPrefix}{cityCode}";
      if (this.DataSources.Contains(dataSourceId))
      {
        return dataSourceId;
      }
      cityCode = ((cityCode.ToInt32Value() / 10000) * 10000).ToString();
      dataSourceId = $"{SiteSettingsBase.DataSourceKeyPrefix}{cityCode}";
      if (this.DataSources.Contains(dataSourceId))
      {
        return dataSourceId;
      }
      return null;
    }

    /// <summary>
    /// 获取参数对象，对参数数据进行特殊处理
    /// </summary>
    /// <param name="param"></param>
    /// <param name="templateName"></param>
    /// <param name="defaultDataSourceId"></param>
    /// <returns></returns>
    protected override IQueryParams GetParam(IQueryParams param, string templateName, string defaultDataSourceId)
    {
      var apiQueryParams = (IAPIQueryParams)base.GetParam(param, templateName, defaultDataSourceId);
      var cityCode = apiQueryParams.CityCode;
      if (cityCode.IsNotNullOrEmpty() && apiQueryParams.DataSource.IsNullOrEmpty())
      {
        //如果参数中未指定数据源且参数中存在cityCode，则根据cityCoed自动切换到对应城市的数据源
        var dataSourceId = this.GetValidDataSource(cityCode);
        if (dataSourceId.IsNullOrEmpty())
        {
          throw new NullReferenceException("无效城市编码！");
        }
        apiQueryParams.DataSource = dataSourceId;
      }
      return apiQueryParams;
    }
  }
}
